package handler

import (
	"context"
	"golang.org/x/crypto/bcrypt"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	"log"
	global2 "shop_srv/user_srv/internal/global"
	"shop_srv/user_srv/internal/model"
	proto2 "shop_srv/user_srv/pkg/proto"
	"time"
)

/**
 * @Description
 * @Author huran
 * @Date
 * @Param
 * @return
 **/

type UserServer struct {
	proto2.UserServer
}

// ModelToResponse 返回指针类型
func ModelToResponse(user model.User) *proto2.UserInfoResponse {
	//在grpc中message中字段有默认值，你不能随便设置nil进去
	res := proto2.UserInfoResponse{Id: user.ID,
		Password: user.Password,
		NickName: user.NickName,
		Gender:   user.Gender,
		Role:     int32(user.Role),
	}
	if user.Birthday != nil {
		res.Birthday = uint64(user.Birthday.Unix())
	}
	return &res
}

// GetUserList 用户列表
func (u *UserServer) GetUserList(ctx context.Context, req *proto2.PageInfo) (*proto2.UserListResponse, error) {
	var users []model.User
	res := global2.DB.Find(&users)
	if res.Error != nil {
		return nil, res.Error
	}
	rsp := &proto2.UserListResponse{}
	rsp.Total = int32(res.RowsAffected)
	global2.DB.Scopes(global2.Paginate(int(req.Pn), int(req.PSize))).Find(&users)
	for _, v := range users {
		response := ModelToResponse(v)
		rsp.Data = append(rsp.Data, response)
	}
	return rsp, nil
}

// GetUserByMobile 通过mobile查询用户
func (u *UserServer) GetUserByMobile(ctx context.Context, req *proto2.MobileRequest) (*proto2.UserInfoResponse, error) {
	var user model.User
	res := global2.DB.Where(&model.User{Mobile: req.Mobile}).First(&user)
	if res.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, "用户不存在")
	}
	if res.Error != nil {
		return nil, res.Error
	}
	response := ModelToResponse(user)
	return response, nil
}

// GetUserById 根据ID查询用户
func (u *UserServer) GetUserById(ctx context.Context, req *proto2.IdRequest) (*proto2.UserInfoResponse, error) {
	var user model.User
	res := global2.DB.First(&user, req.Id)
	if res.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, "用户不存在")
	}
	if res.Error != nil {
		return nil, status.Errorf(codes.Internal, res.Error.Error())
	}
	response := ModelToResponse(user)
	return response, nil
}

// CreateUser 添加用户
func (u *UserServer) CreateUser(ctx context.Context, req *proto2.CreateUserInfo) (*proto2.UserInfoResponse, error) {
	var user model.User
	res := global2.DB.Where(&model.User{Mobile: req.Mobile}).First(&user)
	if res.RowsAffected > 0 {
		return nil, status.Errorf(codes.AlreadyExists, "用户已经存在")
	}
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
	if err != nil {
		return nil, status.Errorf(codes.Internal, res.Error.Error())
	}
	user.Password = string(hashedPassword)
	//密码加密
	res = global2.DB.Create(&user)
	if res.Error != nil {
		return nil, status.Errorf(codes.Internal, res.Error.Error())
	}
	log.Print(res)
	userInfo := ModelToResponse(user)
	return userInfo, nil
}

// UpdateUser 更新用户
func (u *UserServer) UpdateUser(ctx context.Context, req *proto2.UpdateUserInfo) (*emptypb.Empty, error) {
	var user model.User
	res := global2.DB.First(&user, req.Id)
	if res.RowsAffected == 0 {
		return nil, status.Errorf(codes.AlreadyExists, "用户不存在")
	}
	birthDay := time.Unix(int64(req.Birthday), 0)
	user.NickName = req.NickName
	user.Birthday = &birthDay
	user.Gender = req.Gender
	result := global2.DB.Save(&user)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	return &emptypb.Empty{}, nil
}
func (u *UserServer) CheckPasswordInfo(ctx context.Context, req *proto2.PasswordCheckInfo) (*proto2.CheckPasswordResponse, error) {
	var user model.User
	res := global2.DB.First(&user, req.Id)
	if res.RowsAffected == 0 {
		return nil, status.Errorf(codes.AlreadyExists, "用户不存在")
	}
	// 用户输入的密码
	passwordAttempt := []byte(req.Password)
	// 检查密码是否匹配
	err := bcrypt.CompareHashAndPassword([]byte(user.Password), passwordAttempt)
	if err != nil {
		return &proto2.CheckPasswordResponse{Success: false}, status.Errorf(codes.Internal, "密码不匹配")
	}
	return &proto2.CheckPasswordResponse{Success: true}, nil
}
